Armold is a 5-DOF robotic arm built with help from Sweep Dynamics, whose mechanical design it's based on. I built it around a completely different electronics and control stack — new motors, a CAN bus architecture, a custom ros2_control hardware interface, and modified printed parts to fit it all. The goal was a platform that runs a real motion-planning stack end to end: Cartesian goal poses down through inverse kinematics to closed-loop motors on a CAN bus.
The joints are driven by MKS Servo42D closed-loop steppers in SR_vFOC mode, each on its own CAN ID (01–05). Output reduction comes from 1:26 cycloidal drives designed by Sweep Dynamics — high ratio in a compact envelope, low backlash, and enough torque density to hold the arm's weight without sagging between planning cycles. Backlash matters more than it seems: every degree of slop at a joint compounds through the kinematic chain into end-effector error, degrading how well the computed IK solution matches reality.
Integrating the reducers wasn't drop-in — I modified the provided models to match my motor mounts, shaft interface, and printer tolerances. Two lessons from that:
The gripper is a hobby PWM servo driven by an ESP32 over LEDC, on its own 5–6 V supply, kept separate from the CAN side.
Armold is a 5-DOF serial chain — base yaw, shoulder pitch, elbow pitch, wrist pitch, and wrist roll — terminating in a fixed tool0 frame at the gripper mount, described in a URDF with each joint's axis and origin pulled from CAD.
Forward kinematics chains the joint transforms into a tool pose; inverse kinematics solves the useful direction — given a desired pose, what joint angles reach it — which is what makes the arm commandable in task space instead of joint space. MoveIt 2 solves this numerically from the URDF via KDL. A few implications worth knowing:
A Raspberry Pi 4 runs the stack, talking to the motor bus through an MKS CANable V2.0 Pro USB-CAN adapter, bridged into ROS 2 with ros2_socketcan on can0 at 500 kbit/s. The bus is a daisy chain of CANH/CANL with 120 Ω termination at both ends, motor power on a separate parallel rail.
Things that cost me time:
ROS 2 Jazzy with MoveIt 2 and ros2_control, split across three packages:
my_arm_description — URDF and meshes, the source of truth for the kinematic chainmy_arm_moveit_config — SRDF, planning group, kinematics solver config, joint limitsmy_arm_hardware — a custom SystemInterface plugin (ArmSystem) owning the CAN read/write path to the Servo42D boardsDevelopment happens on a Windows 11 laptop through WSL2 (Ubuntu 24.04); the Pi runs headless over SSH as the deployment target, with CycloneDDS handling middleware across the two. I got the full pipeline running against mock hardware first — move_group, controller_manager, joint_state_broadcaster, arm_controller, and /joint_states all healthy — before swapping in real motors, so hardware bugs stayed isolated from planning/IK bugs.
The failures that ate the most hours were almost all configuration, not code:
joint_limits.yaml must set has_acceleration_limits: true and a max_acceleration. Without them, IK resolves, OMPL finds a plan, and AddTimeOptimalParameterization silently fails on every one — RViz shows nothing useful, the real error only shows in rqt_console.install/ caused multi-hour ghost-hunts — building only the package you're actively editing isn't enough.ros2_control_node gets robot_description from the /robot_description topic published by robot_state_publisher, not as a node parameter. Passing it as a parameter starves the controller manager with no obvious complaint.ros2_controllers.yaml and live in the MoveIt config package's config/ directory for MoveItConfigsBuilder to pick it up — anywhere else and it's silently ignored.-11 on shutdown is usually just Ctrl+C teardown noise, not a startup segfault — check ros2 node list before assuming a crash.Next up is finishing the real CAN command implementation in the hardware interface's read()/write() bodies, then adding a camera. Longer term, the goal is using Armold as a platform for LeRobot/VLA experimentation, with the ros2_control hardware interface bridging learned policies to the motors.
One constraint already run into: the Servo42D closed-loop steppers aren't backdrivable, so kinesthetic teaching isn't practical with this hardware — any demonstration pipeline will have to come from teleoperation instead.